#-*-coding:utf-8-*-
'''
This module will organise the modules to accomplish a whole procedure step.
@Author:liuhucheng
@Time:17/05/2012 14:41
'''
from fileoperate import FileOperate
from FinalCompress import FinalCompress
from runlengthencode import RunLengthEncode
from Huffman import Huffman
from coding import *
from jpgmodule import myJpg
from myZip import myZip
import pickle
#import sys,getopt

class myAlgorithm:
    '''
    This module will accomplish the whole step.
    '''
    def __init__(self):
        pass

    def Encoding(self,pathname):
        '''
        Encoding,pathname is the file.
        '''
        #readlen = 254           #read length
        readlen = 255
        fo = FileOperate()      #read files
        fo.OpenReadFile(pathname)
        k = fo.ReadFileByBytes(readlen)
        fc = FinalCompress()        #init to compress files by readlen
        outstr = ''
        while (k != False):
            klen = len(k)       #the real length
            for i in range(klen):
                fc.AddByte(k[i],i)
            outstr += fc.GetDataStr()
            fc.__init__()       #clear the data memory
            k = fo.ReadFileByBytes(readlen)
        rle = RunLengthEncode()
        outbin = rle.Encoding(outstr)
        hfm = Huffman()         #Huffman encoding
        outstr = hfm.Encoding(outbin)
        return outstr

    def Encoding2(self,ostr):
        '''
        Another encoding style.
        '''
        fc = FinalCompress()
        outstr = fc.Encoding(ostr)
        rle = RunLengthEncode()
        outbin = rle.Encoding(outstr)
        hfm = Huffman()
        outstr = hfm.Encoding(outbin)
        return outstr

    def Decoding(self,pathname):
        '''
        This function is used to decode the encoding string.
        '''
        #readlen = 255
        fo = FileOperate()
        k = fo.ReadAllBytes(pathname)       #get the file content.
        interstr = self.RunLengthAndHuffmandecode(k)    #get the Matrix DataStr
        fc = FinalCompress()
        s = fc.Decoding(interstr)
        return s

    def EncodingStr(self,stren):
        '''
        This function is used to encoding a string not a file.
        '''
        readlen = 255           #the zero is used as a flag.
        clen = len(stren)
        outstr = ''
        fc = FinalCompress()
        for i in range(0,clen,readlen):
            if clen - i < readlen:      #last strbits
                suben = stren[i:]
            else:
                suben = stren[i:i + readlen]
            for j in enumerate(suben,0):
                fc.AddByte(j[1],j[0])
            outstr += fc.GetDataStr()
            fc.__init__()
        rle = RunLengthEncode()
        outbin = rle.Encoding(outstr)
        hfm = Huffman()
        outstr = hfm.Encoding(outbin)
        return outstr

    def EncryptOnly(self,pathname,initkey,dstpath):
        '''
        Encrypt the image only.
        '''
        myjpg = myJpg()
        print 'Openning the image!'
        myjpg.openfile(pathname)        #open the image file
        myjpg.getData()
        en = CodeAlogrithm()
        print 'Permutate the pixels!'
        s = en.Permute(myjpg.imagedata,myjpg.im.size,initkey[0])
        print 'Substituting...'
        s = en.Substitute(s,initkey[1])
        print 'Substitute is done!'
        print 'Converting string to tuples...'
        ldata = en.codecom.StrToData(s)
        print 'Convert string to tuples is done!'
        if myjpg.putData(ldata):
            print 'putData is done!'
            myjpg.SaveAs(dstpath)
            print 'Save image is done!'

    def DecryptOnly(self,pathname,initkey,dstpath):
        '''
        Decrypt the image. the oppsite procedured to EncryptOnly.
        '''
        myjpg = myJpg()
        en = DecodingAlgorithm()
        print 'Openning the image!'
        myjpg.openfile(pathname)        #open the image file
        s = myjpg.tostring()

        print 'Substituting...'
        s = en.Substitute(s,initkey[1])
        print 'Substitute is done!'

        print 'Permuting...'
        myjpg.imagedata = en.Permute(s,myjpg.im.size,initkey[0])
        print 'Permuting is done!'

        print 'Saving image!'
        myjpg.SaveAs(dstpath)
        print 'All is done!'

    def EncryptFile(self,pathname,initkey,Istest,dstpath):
        '''
        Encrypt image by view the image as binary streams.
        '''
        fo = FileOperate()          #the file operate class.
        en = CodeAlogrithm()
        s = fo.ReadAllBytes(pathname)       #read all bytes in the file.

        #k = en.codecom.GetRWidth(initkey[2])
        k = en.codecom.NewGenerateKeys(initkey[2],1,16)
        
        s = self.PaddingBytesFile(s,k)

        s = en.codecom.StrToData(s)
        size = self.CalcRowColFile(s,k)
        #print size


        #print len(s)
        #print size
        print 'Permuting...'
        s = en.Permute(s,size,initkey[0])
        print 'Permutation is done!'
        #print len(s)

        #the same
        print 'Runlength and Huffman coding!'
        s = self.RunLengthAndHuffmancode(s)
        print 'Runlength and Huffman coding is done.'

        if Istest:
            print 'Filling bytes!'
            print len(s)
            #size = [en.codecom.forint(len(s) / (3.0 * 128)),128]
            size = [513,513]
            #s = self.PaddingBytesPixels(s,size)          #filling
            s = self.LPaddingBytesPixels(s,size)
            print 'Filling bytes is done!'

        #print len(s)
        print 'Substituting...'
        s = en.Substitute(s,initkey[1])
        print 'Substitute is done!'

        if Istest:
            myjpg = myJpg()
            #myjpg.mode = 'RGB'
            #myjpg.mode = 'L'
            #myjpg.info = [(72,72),size]
            #print 'Converting string to tuples...'
            #ldata = en.codecom.StrToData(s)
            #print 'Convert string to tuples is done!'
            #myjpg.imagedata = ldata
            #print 'putData is done!'
            #myjpg.SaveAs(dstpath)
            myjpg.SaveLAs(dstpath,s,size)
            print 'Save image is done!'

        else:
            #myzip = myZip()
            print 'Write File...'
            #myzip.OpenZipFile(dstpath,'w')
            #myzip.WriteZipFile(s,'content')
            #myzip.CloseZipFile()
            fo.WriteFileStr(dstpath,s)
            print 'All done!'

    def DecryptFile(self,pathname,initkey,Istest,dstpath):
        '''
        the decode procedure of EncryptFile.
        '''
        en = DecodingAlgorithm()
        fo = FileOperate()          #the file operate class.
        if Istest:
            pass
        else:
            #myzip = myZip()
            print 'Openning file..'
            #myzip.OpenZipFile(pathname,'r')
            #s = myzip.ReadZipFileByName('content')
            s = fo.ReadAllBytes(pathname)

        print 'Substituting...'
        s = en.Substitute(s,initkey[1])
        print 'Substitute is done!'

        print 'Runlength and Huffman decoding!'
        s = self.RunLengthAndHuffmandecode(s)
        print 'Runlength and Huffman decoding is done.'
        #the same

        print 'Statistics ...'
        #k = en.codecom.GetRWidth(initkey[2])
        k = en.codecom.NewGenerateKeys(initkey[2],1,16)
        size = self.CalcStrRowColFile(s,k)
        #print size
        print 'Statistics is done!'

        #print size
        #print len(s)
        print 'Permuting...'
        s = en.Permute(s,size,initkey[0])
        print 'Permuting is done!'
        #print len(s)


        print 'Data Formating..'
        s = en.codecom.DataToStr(s)
        print 'Formating done!'

        print 'UnPadding ..'
        s = self.UnPaddingBytesFile(s)
        print 'Unpadding done!'

        print 'Saving image...'
        fo.WriteFileStr(dstpath,s)
        print 'All is done!'

    def CalcStrRowColFile(self,s,width = 64):
        '''
        calc the str
        '''
        k = len(s)
        return [k / (3 * width),width]

    def CalcRowColFile(self,s,width = 64):
        '''
        calc the rows and the cols of the s.
        '''
        k = len(s)
        return [k / width,width]

    def PaddingBytesFile(self,s,width = 64,flag = '\xff'):
        '''
        fill the bytes to ensure the Permutation can apply properly .
        the width decide the width of the rows.
        the defualt fill byte is '\xff' which is the flag byte in jpg documentary.
        '''
        s += '\xd9\x00\xd9'
        klent = len(s)
        k = klent % (3 * width)
        s += ((3 * width - k) * flag)
        return s

    def UnPaddingBytesFile(self,s,flag = '\xd9\x00\xd9'):
        '''
        to discart the filling bytes.
        '''
        pos = s.rfind(flag)  #search begin at the end of the string
        if pos == -1:
            return ''
        else:
            #return  s[:pos + 1]     #get the content
            return  s[:pos]     #get the content

    def EncryptPixels(self,pathname,initkey,Istest,dstpath):
        '''
        the final encoding function
        pathname is the file.
        initkey is the key.
        Istest means the function is test or using.
        '''
        myjpg = myJpg()
        print 'Openning the image!'
        myjpg.openfile(pathname)        #open the image file
        myjpg.getData()
        en = CodeAlogrithm()
        print 'Permutate the pixels!'
        s = en.Permute(myjpg.imagedata,myjpg.im.size,initkey[0])
        print 'Runlength and Huffman coding!'
        s = self.RunLengthAndHuffmancode(s)
        print 'Runlength and Huffman coding is done.'
        if Istest:
            print 'Filling bytes!'
            s = self.PaddingBytesPixels(s,myjpg.im.size)          #filling
            print 'Filling bytes is done!'
        print 'Substituting...'
        s = en.Substitute(s,initkey[1])
        print 'Substitute is done!'
        if Istest:
            #print len(s)
            print 'Converting string to tuples...'
            ldata = en.codecom.StrToData(s)
            #print len(ldata)
            print 'Convert string to tuples is done!'
            #print ldata
            if myjpg.putData(ldata):
                print 'putData is done!'
                myjpg.SaveAs(dstpath)
                print 'Save image is done!'
        else:
            infostr = myjpg.getStrInfoAndSize()
            myzip = myZip()
            print 'Write File...'
            myzip.OpenZipFile(dstpath,'w')
            myzip.WriteZipFile(infostr,'info')
            myzip.WriteZipFile(s,'content')
            myzip.WriteZipFile(pickle.dumps(myjpg.mode),'mode')
            myzip.CloseZipFile()
            print 'All done!'

    def DecryptPixels(self,pathname,initkey,Istest,dstpath):
        '''
        the parameters is the same as the encrypt.
        '''
        myjpg = myJpg()
        en = DecodingAlgorithm()
        if Istest:
            print 'Openning the image!'
            myjpg.openfile(pathname)        #open the image file
            #myjpg.getData()
            s = myjpg.tostring()
        else:
            myzip = myZip()
            print 'Openning file..'
            myzip.OpenZipFile(pathname,'r')
            myjpg.info = myjpg.getInfoAndSize(myzip.ReadZipFileByName('info'))          #get the info of the pic
            #print myjpg.info
            myjpg.mode = pickle.loads(myzip.ReadZipFileByName('mode'))
            s = myzip.ReadZipFileByName('content')
        print 'Substituting...'
        s = en.Substitute(s,initkey[1])
        print 'Substitute is done!'
        print 'Runlength and Huffman decoding!'
        s = self.RunLengthAndHuffmandecode(s)
        print 'Runlength and Huffman decoding is done.'
        print 'Permuting...'
        myjpg.imagedata = en.Permute(s,myjpg.info[1],initkey[0])
        print 'Permuting is done!'
        print 'Saving image!'
        myjpg.SaveAs(dstpath)
        print 'All is done!'

    def PaddingBytesPixels(self,ins,info):
        '''
        Filling the picture to make the size the same as the original size.
        '''
        lent = len(ins)
        #print lent
        #print info
        #print 3 * info[0] * info[1] -lent
        if lent < 3 * info[0] * info[1]:
            ins += ((3 * info[0] * info[1] - lent) * '\xff')                #filling with 255
        return ins
        
    def LPaddingBytesPixels(self,ins,info):
        '''
        Filling the picture to make the size the same as the original size.
        '''
        lent = len(ins)
        if lent < info[0] * info[1]:
            ins += ((info[0] * info[1] - lent) * '\xff')                #filling with 255
        return ins

    def RunLengthAndHuffmancode(self,strcd):
        '''
        This module is use to encode the str by using runlength coding and huffman coding.
        '''
        rle = RunLengthEncode()
        outbin = rle.Encoding(strcd)
        hfm = Huffman()
        outstr = hfm.Encoding(outbin)
        return outstr

    def RunLengthAndHuffmandecode(self,strcd):
        '''
        This function is use to decode the srt by using runlength coding and huffman coding
        '''
        hfm = Huffman()
        outstr = hfm.Decoding(strcd)
        rle = RunLengthEncode()
        outstr = rle.Decoding(outstr)
        return outstr

    def EncodingN(self,pathname,ktimes):
        '''
        coding n times
        '''
        fo = FileOperate()
        k = fo.ReadAllBytes(pathname)
        s = self.EncodingStr(k)
        for i in range(ktimes - 1):
            s = self.RunLengthAndHuffmancode(s)
        return s

    def test6(self):
        '''
        run length and huffman
        '''
        avf = open('1.txt','rb')
        c = avf.read()
        avf.close()

        #hfm = Huffman()
        c = self.RunLengthAndHuffmancode(c)
        #c = hfm.Encoding(c)
        avf = open('rfe1.txt','wb')
        avf.write(c)
        avf.flush()
        avf.close()

        #c = hfm.Decoding(c)
        c = self.RunLengthAndHuffmandecode(c)
        avf = open('11.txt','wb')
        avf.write(c)
        avf.flush()
        avf.close()

    def test5(self):
        '''
        test decoding.
        '''
        s = self.Decoding('e1.txt')
        avf = open('e11.txt','wb')
        avf.write(s)
        avf.flush()
        avf.close()

    def test4(self):
        '''
        test encoding and encoding2
        '''
        s = self.Encoding('pure.txt')
        avf = open('e1.txt','wb')
        avf.write(s)
        avf.flush()
        avf.close()

        #avf = open('alarm.tiff','rb')
        #k = avf.read()
        #avf.close()
        #c = self.Encoding2(k)

        #avf = open('e2.txt','wb')
        #avf.write(c)
        #avf.flush()
        #avf.close()

    def test3(self):
        '''
        test the module.
        '''
        c = self.EncodingN('alarm.tiff',3)
        avf = open('ntest.txt','wb')
        avf.write(c)
        avf.flush()
        avf.close()

    def test2(self):
        '''
        test encoding and encodingstr
        '''
        s = self.Encoding('alarm.tiff')
        avf = open('1.txt','wb')
        avf.write(s)
        avf.flush()
        avf.close()

        avf = open('alarm.tiff','rb')
        c = avf.read()
        avf.close()
        k = self.EncodingStr(c)
        avf = open('2.txt','wb')
        avf.write(k)
        avf.flush()
        avf.close()

    def test(self):
        '''
        test
        '''
        s = self.Encoding('alarm.tiff')
        hfm = Huffman()
        l = self.countrun(s)
        #print l
        avf = open('runout.txt','wb')
        avf.write(s)
        avf.flush()
        avf.close()
        s = hfm.Encoding(s)
        avf = open('out1.txt','wb')
        avf.write(s)
        avf.flush()
        avf.close()

    def countrun(self,sstr):
        c = list(sstr)
        l = dict()
        for i in range(len(c)):
            if not l.has_key(c[i]):
                l[c[i]] = c.count(c[i])
        return l

if __name__ == "__main__":
    c = myAlgorithm()
    #c.test4()
    #c.test5()
    #c.test6()
    #c.Encrypt('/home/hucheng/workspace/graduateproject/image-compress-encrypt/res/1.jpg',[2,2],False,'/home/hucheng/workspace/graduateproject/image-compress-encrypt/res/en.jpg')
    #c.Decrypt('/home/hucheng/workspace/graduateproject/image-compress-encrypt/res/en.jpg',[2,2],False,'/home/hucheng/workspace/graduateproject/image-compress-encrypt/res/0.jpg')
    c.EncryptFile('E:\\workspace\\graduateprject\\module\\image-compress-encrypt\\res\\couple.tiff',[0.3,0.6,0.45],True,'E:\\workspace\\graduateprject\\module\\image-compress-encrypt\\res\\key1.jpg')
    #c.DecryptFile('/home/hucheng/workspace/graduateproject/image-compress-encrypt/res/ef.jpg',[2,2,2],False,'/home/hucheng/workspace/graduateproject/image-compress-encrypt/res/def.jpg')
    #c.EncryptOnly('/home/hucheng/workspace/graduateproject/image-compress-encrypt/res/1.jpg',[2,2],'/home/hucheng/workspace/graduateproject/image-compress-encrypt/res/oe.jpg')
    #c.DecryptOnly('/home/hucheng/workspace/graduateproject/image-compress-encrypt/res/oe.jpg',[2,2],'/home/hucheng/workspace/graduateproject/image-compress-encrypt/res/oe1.jpg')
